<template>
  <!-- tablecommon -->
  <div class="calendarDayBox">
    <div class="calendarDay-card-header aic jcb">
      <!-- <h3>{{ state.currentDate }}</h3> -->
      <div>
        <el-select
          style="width: 100px"
          v-model="state.selectYear"
          @change="handleYear"
          filterable
          placeholder="请选择"
        >
          <el-option
            v-for="item in state.years"
            :key="item"
            :label="item"
            :value="item"
          >
            {{ item }}
          </el-option>
        </el-select>
        <el-select
          style="width: 100px; margin-left: 20px"
          v-model="state.selectMonth"
          @change="handleMonth"
          filterable
          placeholder="请选择"
        >
          <el-option
            v-for="item in state.months"
            :key="item"
            :label="item"
            :value="item"
          >
            {{ item }}
          </el-option>
        </el-select>
      </div>
      <el-radio-group v-model="state.currentButtonValue">
        <el-radio-button label="1">上个月</el-radio-button>
        <el-radio-button label="2">本月</el-radio-button>
        <el-radio-button label="3">下个月</el-radio-button>
      </el-radio-group>
    </div>
    <el-divider></el-divider>
    <div class="calendarWeek aic jca">
      <div>周一</div>
      <div>周二</div>
      <div>周三</div>
      <div>周四</div>
      <div>周五</div>
      <div>周六</div>
      <div>周日</div>
    </div>
    <div
      v-if="state.clendaritemList"
      class="calendarDayHeightAuto calendarDay-content"
    >
      <template v-for="(date, index) in state.clendaritemList" :key="index">
        <el-badge
          :hidden="verifyNum(dayjs(date).format('YYYY-MM-DD')).length == 0"
          :value="verifyNum(dayjs(date).format('YYYY-MM-DD')).length"
        >
          <el-dropdown
            trigger="contextmenu"
            style="width: 100%; height: 100%"
            @command="handleCommand($event, index, date)"
          >
            <!-- state.startDateIndex -->

            <div
              class="jcc aic cP   calendarDay-content-item "
              @click="handleClickDate(index)"
              @mouseenter="handleStopRoll(index)"
              :class="[
                state.currentDateIndex == index ? 'calendarDayactive' : '',
                state.endDateIndex == index
                  ? 'calendarDaystartAndEndDateIndex'
                  : '',
                isCurrentMonth(date) ? 'calendarDayColor' : 'calendarDayOther',
                state.startDateIndex == index
                  ? 'calendarDaystartAndEndDateIndex'
                  : '',
                isScopeOf(index) != -1
                  ? 'calendarDaystartAndEndDateIndexScopeOf'
                  : '',
              ]"
            >
              <span class="calendarDayel-dropdown-link w100 h100">
                <el-popover
                  class="w100 h100"
                  :width="width"
                  :trigger="
                    verify(dayjs(date).format('YYYY-MM-DD'))
                      ? 'hover'
                      : 'manual'
                  "
                >
                  <template #reference>
                    <div class="w100 h100">
                      <slot name="content" :data="{ date }">
                        {{ dayjs(date).format("YYYY-MM-DD") }}
                      </slot>
                    </div>
                  </template>
                  <slot
                    name="popover"
                    :data="verifyNum(dayjs(date).format('YYYY-MM-DD'))"
                  >
                  </slot>
                </el-popover>
              </span>
            </div>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item command="current">添加日程</el-dropdown-item>
                <el-dropdown-item command="scopeOf"
                  >添加日程范围选择</el-dropdown-item
                >
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-badge>
      </template>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, watch, nextTick } from "vue";
const colors = ["#409EFF", "#019A61", "#333333"];
const getColor = () => {
  return colors[Math.floor(Math.random() * colors.length)];
};

import dayjs from "dayjs";
let props: any = defineProps({
  width: {
    type: Number,
    default: 400, //气泡弹出框 鼠标悬浮触发
  },
  popoverData: {
    type: Array,
    default: [], //有时间才有气泡弹出功能 date YYYY-MM-DD
  },
  placement: {
    type: String,
    default: "bottom",
    /**
     * top/top-start/top-end/bottom/bottom-start/
     * bottom-end/left/left-start/left-end/right/
     * right-start/right-end
     */
  },
});

const verifyNum = (str: string) => {
  let bool = 0;
  for (let index = 0; index < props.popoverData.length; index++) {
    const element = props.popoverData[index];
    if (element.date == str) {
      bool = element.list;
      break;
    }
  }
  return bool;
};
const verify = (str: string) => {
  let bool = false;
  for (let index = 0; index < props.popoverData.length; index++) {
    const element = props.popoverData[index];
    if (element.date == str) {
      bool = true;
      break;
    }
  }
  return bool;
};
let emit = defineEmits([
  "handleCurrentEvent",
  "handleCurrent",
  "handleScopeOf",
]);

onMounted(() => {
  initDate();
});
/*
基本数据类型
引用数据类型（复杂类型） 个人建议 ref初始化变量 
ref 和 reactive 本质我们可以简单的理解为ref是对reactive的二次包装, 
ref定义的数据访问的时候要多一个.value
*/

const state: any = reactive({
  years: [],
  months: [],
  selectMonth: 1,
  selectYear: 1,
  currentDateIndex: -1,
  currentButtonValue: "2",
  clendaritemList: [], //42个元素
  currentDate: dayjs().format("YYYY-MM"),
  startDateIndex: -1,
  endDateIndex: -1,
  isScopeOf: false, //true 是范围选择 false 不是 单选
  scopeOfArrIndex: [],
});

const totalDay = 42; //6*7 一页展示多少天
const weekDay = 7; //6*7 一星期有几天
const getMonthDay = (year: number, month: number) => {
  let days = new Date(year, month + 1, 0).getDate();
  return days;
};

/**
 * 判断是否是当前月份
 */
const isCurrentMonth = (el: Date) => {
  let valDate = el.getMonth();
  return state.selectMonth - 1 == valDate;
};
/**
 * 初始化日期
 */
const initDate = () => {
  state.months = [];
  state.years = [];
  for (let index = 1; index <= 12; index++) {
    state.months.push(index);
  }

  for (let index = 1900; index <= new Date().getFullYear() + 20; index++) {
    state.years.push(index);
  }
};
/**
 * 选取月
 */
const handleMonth = (index: number) => {
  reset(() => {
    getInit(state.selectYear, index - 1);
  });
};
/**
 * 选取年
 */
const handleYear = (index: number) => {
  reset(() => {
    getInit(index, state.selectMonth - 1);
  });
};
/**
 * 当前是否是选择范围内的元素
 */
const isScopeOf = (index: number) => {
  let bool = false;
  return state.scopeOfArrIndex.indexOf(index);
};
const getInit = (year: number, month: number) => {
  let last: any, next: any, current: any; //天数
  /**
   * 0是星期天 6是星期六
   */
  last = {
    day: [], //一共有几天
    lastweek: 0, //第一天是星期几
    nextweek: 0, //最后天是星期几
  };
  next = {
    day: [], //一共有几天
    lastweek: 0, //第一天是星期几
    nextweek: 0, //最后天是星期几
  };
  current = {
    day: [], //一共有几天
    lastweek: 0, //第一天是星期几
    nextweek: 0, //最后天是星期几
  };
  /**
   * 当前月
   */
  let day = getMonthDay(year, month);
  for (let index = 1; index <= day; index++) {
    current.day.push(index);
  }
  current.lastweek = new Date(`${year}/${month + 1}/1`).getDay();

  if (current.lastweek == 0) {
    current.lastweek = 7;
  }
  current.nextweek = new Date(`${year}/${month + 1}/${day}`).getDay();
  if (current.nextweek == 0) {
    current.nextweek = 7;
  }
  /*
    上一个月
    */
  if (month == 0) {
    //上个月 判断月份 如果是当前月份是0 年份减一 月份==11
    let yearlast = year - 1;
    let month = 11;
    //   last = getMonthDay(year,month)
    let day = getMonthDay(yearlast, month);
    for (let index = 1; index <= day; index++) {
      last.day.push(index);
    }
    last.lastweek = new Date(`${yearlast}/${month + 1}/1`).getDay();
    last.nextweek = new Date(`${yearlast}/${month + 1}/${day}`).getDay();
    if (last.lastweek == 0) {
      last.lastweek == 7;
    }
    if (last.nextweek == 0) {
      last.nextweek == 7;
    }
  } else if (month > 0 && month <= 11) {
    //年份不动月份改

    let monthlast = month - 1;
    let day = getMonthDay(year, monthlast);
    for (let index = 1; index <= day; index++) {
      last.day.push(index);
    }
    last.lastweek = new Date(`${year}/${monthlast}/1`).getDay();
    last.nextweek = new Date(`${year}/${monthlast}/${day}`).getDay();
    if (last.lastweek == 0) {
      last.lastweek == 7;
    }
    if (last.nextweek == 0) {
      last.nextweek == 7;
    }
  }

  /*
    下一个月
    */
  if (month >= 0 && month < 11) {
    //上个月 判断月份 如果是当前月份是0 年份减一 月份==11
    //年份不动月份改
    let monthlast = month + 1;
    let day = getMonthDay(year, monthlast);
    for (let index = 1; index <= day; index++) {
      next.day.push(index);
    }
    next.lastweek = new Date(`${year}/${monthlast + 1}/1`).getDay();
    next.nextweek = new Date(`${year}/${monthlast + 1}/${day}`).getDay();
    if (next.lastweek == 0) {
      next.lastweek == 7;
    }
    if (next.nextweek == 0) {
      next.nextweek == 7;
    }
  } else if (month == 11) {
    // 年份+1 月份=0
    let yearnext = year + 1;
    let month = 0;
    let day = getMonthDay(yearnext, month);
    for (let index = 1; index <= day; index++) {
      next.day.push(index);
    }
    next.lastweek = new Date(`${yearnext}/${month + 1}/1`).getDay();
    next.nextweek = new Date(`${yearnext}/${month + 1}/${day}`).getDay();
    if (next.lastweek == 0) {
      next.lastweek == 7;
    }
    if (next.nextweek == 0) {
      next.nextweek == 7;
    }
  }

  /**
   * 获取当前月份 是第一条 还有组后一天是星期几
   */
  console.log("current :>> ", current);
  if (current.lastweek == 1) {
    for (let index = 1; index <= current.day.length; index++) {
      state.clendaritemList.push(new Date(`${year}/${month + 1}/${index}`));
    }
    const nextDay = totalDay - current.day.length;
    const nextnum = next.day.slice(0, nextDay);

    for (let index = 1; index <= nextnum.length; index++) {
      //当前月是11 说明是一年最后一个月 所以要下个月展示日期年份+1
      if (month == 11) {
        // 年份+1 月份=0
        let yearnext = year + 1;
        state.clendaritemList.push(new Date(`${yearnext}/${1}/${index}`));
      } else if (month >= 0 && month < 11) {
        state.clendaritemList.push(new Date(`${year}/${month + 2}/${index}`));
      }
    }
  } else if (current.lastweek > 1) {
    let lastDayNum = current.lastweek - 1;
    const num = last.day.length; //获取上个月天数
    /**
     * 补全上个月末尾天数
     */
    const lastnum = last.day.slice(num - lastDayNum);

    for (let index = 0; index < lastnum.length; index++) {
      let ele = lastnum[index];
      if (month == 0) {
        // 年份+1 月份=0
        let yearnext = year - 1;
        state.clendaritemList.push(new Date(`${yearnext}/${12}/${ele}`));
      } else if (month > 0 && month <= 11) {
        state.clendaritemList.push(new Date(`${year}/${month}/${ele}`));
      }
    }
    /**
     * 补全当前一个月天数
     */
    for (let index = 1; index <= current.day.length; index++) {
      state.clendaritemList.push(new Date(`${year}/${month + 1}/${index}`));
    }
    /**
     * 补全下一个月天数
     */
    let nextnum = state.clendaritemList.length;
    for (let index = 1; index <= totalDay - nextnum; index++) {
      if (month == 11) {
        // 年份+1 月份=0
        let yearnext = year + 1;
        state.clendaritemList.push(new Date(`${yearnext}/${1}/${index}`));
      } else if (month >= 0 && month < 11) {
        state.clendaritemList.push(new Date(`${year}/${month + 2}/${index}`));
      }
    }
  }
};
/**
 * 日历回调事件
 */
const handleCommand = (val: string, index: number, date: Date) => {
  switch (val) {
    case "current":
      state.currentDateIndex = index;
      state.isScopeOf = false;
      emit("handleCurrentEvent", {
        date,
        next,
      });

      break;
    case "scopeOf":
      state.currentDateIndex = -1;
      state.isScopeOf = true;
      state.startDateIndex = index;
      break;
  }
};
/**
 * 日历单点击
 */

const handleStopRoll = (index: number) => {
  if (state.isScopeOf) {
    /**
     * 1 如果是开始索引就return
     * 2 如果不是就判断当前索引与开始索引大小对比
     */
    if (state.endDateIndex != -1 && state.startDateIndex != -1) return;
    if (state.startDateIndex == index) return;
    state.scopeOfArrIndex = [];
    //当前悬浮索引值不会等于 开始值所以不存在等于0
    const difference = state.startDateIndex - index; //前后索引差值
    const abs = Math.abs(difference);
    //
    if (state.startDateIndex - index > 0) {
      //说明鼠标在当前索引值之前
      for (let j = state.startDateIndex; j >= index; j--) {
        state.scopeOfArrIndex.push(j);
        state.scopeOfArrIndex = Array.from(new Set(state.scopeOfArrIndex));
      }
    } else {
      //说明鼠标在当前索引值之后
      for (let j = state.startDateIndex; j <= index; j++) {
        state.scopeOfArrIndex.push(j);
        state.scopeOfArrIndex = Array.from(new Set(state.scopeOfArrIndex));
      }
    }
  }
};

const reset = (callback: Function) => {
  state.currentDateIndex = -1;
  state.startDateIndex = -1;
  state.endDateIndex = -1;
  state.isScopeOf = false;
  state.scopeOfArrIndex = [];
  state.clendaritemList = [];
  callback && callback();
};
const next = () => {
  state.currentDateIndex = -1;
  state.startDateIndex = -1;
  state.endDateIndex = -1;
  state.isScopeOf = false;
  state.scopeOfArrIndex = [];
};
const handleClickDate = (index: number) => {
  if (state.endDateIndex != -1 && state.startDateIndex != -1) return;
  if (state.isScopeOf) {
    state.endDateIndex = index;
    state.scopeOfArrIndex = state.scopeOfArrIndex.filter(
      (e: number) => e != index
    );
    //当前是范围选择事件
    emit("handleScopeOf", {
      data: {
        startDate: state.clendaritemList[state.startDateIndex],
        endDate: state.clendaritemList[state.endDateIndex],
      },
      next,
    });
  } else {
    state.currentDateIndex = index;
    emit("handleCurrent", {
      date: state.clendaritemList[index],
    });
  }
};
watch(
  () => state.currentButtonValue,
  (val) => {
    let year = new Date().getFullYear(); //当前年2022
    let month = new Date().getMonth(); //0-11

    state.clendaritemList = [];
    switch (val) {
      case "2":
        state.selectYear = year;
        state.selectMonth = month + 1;
        getInit(year, month);
        break;
      case "1":
        /**
         * 上个月
         */
        if (month == 0) {
          getInit(state.selectYear, 11);
          state.selectYear = year - 1;
          state.selectMonth = 12;
          
        } else {
          getInit(year, month - 1);
          state.selectYear = year;
          state.selectMonth = month;
          
          
        }

        break;
      case "3":
        /**
         * 下个月
         */
        if (month == 11) {
          state.selectYear = year + 1;
          state.selectMonth = 1;
          getInit(year + 1, 0);
        } else {
          state.selectYear = year;
          state.selectMonth = month + 2;
          getInit(year, month + 1);
        }

        break;
    }
  },
  {
    deep: true,
    immediate: true,
  }
);
</script>

<style   lang="scss">
/**.^1.3.0-beta.5 处理这个版本默认 宽度没撑开问题 */
.el-dropdown>div{
width: 100% !important;
}
.el-badge__content.is-fixed {
  transform: translate(10%, 10%);
}
.calendarDaystartAndEndDateIndexScopeOf {
  background-color: #f2f6fc;
  color: #333;
}
.calendarDaystartAndEndDateIndex {
  background-color: #409eff;
  color: #fff !important;
}
.calendarDayOther {
  color: #c0c4cc;
}
.calendarDayColor {
  color: #333;
}
.calendarDayactive {
  background-color: #f2f8fe;
}
.calendarDayBox {
  padding: 10px;
  background-color: #fff;
}
.calendarDay-card-header {
}
.cP {
  cursor: pointer;
}
.calendarWeek {
  padding: 12px 0;
  font-size: 14px;
  > div {
    color: #606266;
    font-weight: 400;
  }
}
.h100 {
  height: 100%;
}
.w100 {
  width: 100%;
}
.calendarDayHeightAuto {
  height: 100px;
  min-height: calc(100% - 160px);
  max-height: calc(100% - 160px);
}
.calendarDay-content {
  margin-top: 25px;
  width: 100%;
  display: grid;

  border: 1px solid #ebeef5;
  grid-template-columns: repeat(7, 14.28%);
  grid-template-rows: repeat(6, 16.66%);
  overflow: hidden;
  border-bottom: none;
  border-right: none;
  .calendarDay-content-item {
    border-right: 1px solid #ebeef5;
    border-bottom: 1px solid #ebeef5;
    margin-right: -1px;
    margin-bottom: -1px;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    position: relative;
  }
  .eventCalendar {
    position: absolute;
    z-index: 1;
    width: 100%;
    height: 100%;
  }
  .calendarDayel-dropdown-link {
  }
  .zindexF {
    position: absolute;
    width: 100%;
    height: 20px;
  }
}
.fd,
.aic,
.jcc,
.jcb,
.jca,
.fdc,
.jcfend {
  display: flex;
}
.aic {
  align-items: center;
}
.jcc {
  justify-content: center;
}
.jcb {
  justify-content: space-between;
}
.jca {
  justify-content: space-around;
}
.jcfend {
  justify-content: flex-end;
}
.fdc {
  flex-direction: column;
}
.flexWrap {
  flex-wrap: wrap;
}
.flex-shrink0 {
  flex-shrink: 0;
}
.flex1 {
  flex: 1;
}
</style>
